﻿using System;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows;
using GeneralTool.CoreLibrary.Models;
using GeneralTool.CoreLibrary.WPFHelper.WPFControls;
using GeneralTool.CoreLibrary.WPFHelper.Extensions;

namespace TaskHostLib
{
    /// <summary>
    /// 参数信息动态生成
    /// </summary>
    public class ItemsDoTaskDependecy : DependencyObject
    {
        /// <summary>
        /// 
        /// </summary>
        public static readonly DependencyProperty ItemsAutoCreateUiProperty = DependencyProperty.RegisterAttached("ItemsAutoCreateUi", typeof(bool), typeof(ItemsDoTaskDependecy), new PropertyMetadata(ItemsChanged));

        /// <summary>
        /// 
        /// </summary>
        /// <param name="control"></param>
        /// <param name="value"></param>
        public static void SetItemsAutoCreateUi(Grid control, bool value) => control.SetValue(ItemsAutoCreateUiProperty, value);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="control"></param>
        /// <returns></returns>
        public static bool GetItemsAutoCreateUi(Grid control) => (bool)control.GetValue(ItemsAutoCreateUiProperty);

        private static void ItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = d as Grid;
            if (e.NewValue != null && (bool)e.NewValue)
                control.DataContextChanged += Control_DataContextChanged;
            else
                control.DataContextChanged -= Control_DataContextChanged;
        }

        private static void Control_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            //自动生成控件
            var grid = sender as Grid;
            grid.Children.Clear();
            grid.RowDefinitions.Clear();
            var model = e.NewValue as DoTaskParameterItem;

            var index = 0;
            foreach (var item in model.Paramters)
            {
                //生成行
                grid.RowDefinitions.Add(new RowDefinition());
                //写入数据
                var txtName = new TextBlock() { Text = item.ParameterName };
                _ = grid.Children.Add(txtName);
                Grid.SetRow(txtName, index);
                Grid.SetColumn(txtName, 0);

                //只支持 string 类型,数值类型,枚举类型,boolean
                //枚举
                if (item.ParameterType.IsEnum)
                {
                    SetEnumUI(grid, item, index);
                }
                else if (item.ParameterType.IsValueType)
                {
                    //值类型
                    if (item.ParameterType == typeof(bool))
                    {
                        SetBooleanUI(grid, item, index);
                    }
                    else
                        SetValueType(grid, item, index);
                }
                else
                {
                    //其它全是string类型
                    SetStringUI(grid, item, index);
                }

                index++;
            }
        }

        private static void SetValueType(Grid grid, ParameterItem item, int index)
        {
            var valueControl = new NumericControl();
            _ = grid.Children.Add(valueControl);
            Grid.SetRow(valueControl, index);
            Grid.SetColumn(valueControl, 1);
            //binding
            valueControl.DataContext = item;
            SetBinding(valueControl, item, NumericControl.ValueProperty);
            _ = double.TryParse(item.Value + "", out var result);
            valueControl.Value = result;

            valueControl.IsDouble = true;
            if (item.ParameterType == typeof(int))
            {
                valueControl.IsDouble = false;
            }
            else if (item.ParameterType == typeof(byte))
            {
                valueControl.Max = byte.MaxValue;
                valueControl.Min = byte.MinValue;
                valueControl.IsDouble = false;
            }
        }

        private static void SetBooleanUI(Grid grid, ParameterItem item, int index)
        {
            var valueControl = new ComboBox
            {
                SelectedItem = item.Value
            };
            _ = grid.Children.Add(valueControl);
            Grid.SetRow(valueControl, index);
            Grid.SetColumn(valueControl, 1);
            //binding
            valueControl.DataContext = item;
            var arr = new bool[] { true, false };
            valueControl.ItemsSource = arr;

            SetBinding(valueControl, item, ComboBox.SelectedItemProperty);

            valueControl.SelectedIndex = !string.IsNullOrWhiteSpace(item.Value + "") ? Array.IndexOf(arr, Convert.ToBoolean(item.Value)) : -1;
        }

        private static void SetEnumUI(Grid grid, ParameterItem item, int index)
        {
            var valueControl = new ComboBox
            {
                SelectedItem = item.Value
            };
            _ = grid.Children.Add(valueControl);
            Grid.SetRow(valueControl, index);
            Grid.SetColumn(valueControl, 1);
            //binding
            valueControl.DataContext = item;
            Array arr = Enum.GetValues(item.ParameterType);
            valueControl.ItemsSource = arr;

            SetBinding(valueControl, item, ComboBox.SelectedItemProperty);

            valueControl.SelectedIndex = !string.IsNullOrWhiteSpace(item.Value + "") ? Array.IndexOf(arr, Enum.Parse(item.ParameterType, item.Value + "")) : -1;

        }

        private static void SetStringUI(Grid grid, ParameterItem item, int index)
        {
            var valueControl = new TextBox() { Text = item.Value + "" };
            _ = grid.Children.Add(valueControl);
            Grid.SetRow(valueControl, index);
            Grid.SetColumn(valueControl, 1);
            //binding
            valueControl.DataContext = item;

            SetBinding(valueControl, item, TextBox.TextProperty);
        }

        private static void SetBinding(FrameworkElement valueControl, ParameterItem item, DependencyProperty Property)
        {
            var binding = new Binding
            {
                Source = valueControl.DataContext,
                Path = new PropertyPath(nameof(item.Value)),
                Mode = BindingMode.TwoWay,
                UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
            };
            IValueConverter converter = ValueConverter.CreateObjectConverter(item.ParameterType, typeof(string), ConvertFunc, BackFunc);
            binding.Converter = converter;
            _ = valueControl.SetBinding(Property, binding);
            valueControl.ToolTip = item.WaterMark;
        }

        private static object ConvertFunc(ValueConverterObjectArgs arg)
        {
            return string.IsNullOrWhiteSpace(arg.Value + "") && arg.InputType.IsValueType && arg.InputType != typeof(string)
                ? Activator.CreateInstance(arg.InputType)
                : arg.Value + "";
        }

        private static object BackFunc(ValueConverterObjectArgs arg)
        {
            if (arg.Value == null)
            {
                return arg.Value + "";
            }
            if (arg.Value.GetType() == arg.InputType)
            {
                return arg.Value;
            }
            else if (arg.InputType == typeof(string))
            {
                return arg.Value;
            }
            else if (arg.InputType.IsEnum)
            {
                return string.IsNullOrWhiteSpace(arg.Value + "")
                    ? Activator.CreateInstance(arg.InputType)
                    : Enum.Parse(arg.InputType, arg.Value + "");
            }
            else if (arg.InputType.IsValueType)
            {
                return arg.Value;
            }
            return Activator.CreateInstance(arg.InputType);
        }
    }
}
